using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Drawing2D.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace System.Drawing.Drawing2D
{
    #region Enumerations

    public enum FillStyle
    {
        None,
        Solid,
        Image,
        Pattern,
        LinearGradient,
        ABALinearGradient,
        RadialGradient,
        //ConicalGradient,
        RectangularGradient,
        PathGradient,
    }

    /* public enum ImageLayoutMode
    {
        Normal,
        Centered,
        Stretched,
        Tiled,
        TiledFlipX,
        TiledFlipY,
        TiledFlipXY,
    }*/

	/* public enum ShapeGradientStyle
	{
		None,
		VerticalLeft,
		VerticalRight,
		VerticalIn,
		VerticalOut,
		HorizontalUp,
		HorizontalDown,
		HorizontalIn,
		HorizontalOut,
		DiagonalForwardBottom,
		DiagonalForwardTop,
		DiagonalForwardIn,
		DiagonalForwardOut,
		DiagonalBackwardBottom,
		DiagonalBackwardTop,
		DiagonalBackwardIn,
		DiagonalBackwardOut,
		FromTopLeftCorner,
		FromTopRightCorner,
		FromBottomLeftCorner,
		FromBottomRightCorner,
		FromCenterIn,
		FromCenterOut,
	}*/

	#endregion Enumerations

    [TypeConverter(typeof(ExpandableObjectConverter))]
    [Editor(typeof(FillTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
    public class Fill : ICloneable
    {
        private float angle = 0f;
        private float center = 0f;
        private Color color1 = Color.Red;
        private Color color2 = Color.White;
        private Image image;
        private HatchStyle pattern = HatchStyle.Horizontal;
        private FillStyle style = FillStyle.Solid;
        private int transparency = 255;
        private WrapMode wrap = WrapMode.Tile;

        public Fill()
        {
        }

        public event EventHandler Color1Changed;

        public event EventHandler Color2Changed;

        public event EventHandler GradientAngleChanged;

        public event EventHandler GradientCenterChanged;

        public event EventHandler ImageChanged;

        public event EventHandler ImageWrapModeChanged;

        public event EventHandler PatternChanged;

        public event EventHandler StyleChanged;

        public event EventHandler TransparencyChanged;

        [DefaultValue(typeof(Color), "Red")]
        public Color Color1
        {
            get { return color1; }
            set
            {
                if (color1 != value)
                {
                    color1 = value;
                    if (Color1Changed != null)
                        Color1Changed(this, new EventArgs());
                }
            }
        }

        [DefaultValue(typeof(Color), "White")]
        public Color Color2
        {
            get { return color2; }
            set
            {
                if (color2 != value)
                {
                    color2 = value;
                    if (Color2Changed != null)
                        Color2Changed(this, new EventArgs());
                }
            }
        }

        [DefaultValue(0f)]
        [Editor(typeof(DegreeTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public float GradientAngle
        {
            get { return angle; }
            set
            {
                if (angle != value)
                {
                    angle = value;
                    if (GradientAngleChanged != null)
                        GradientAngleChanged(this, new EventArgs());
                }
            }
        }

        [DefaultValue(0f)]
        public float GradientCenter
        {
            get { return center; }
            set
            {
                if (value < -1.0f || value > 1.0f)
                    throw new ArgumentOutOfRangeException("value", value, "GradientCenter must be a value between -1.0 and 1.0");
                if (center != value)
                {
                    center = value;
                    if (GradientCenterChanged != null)
                        GradientCenterChanged(this, new EventArgs());
                }

            }
        }

        [DefaultValue(null)]
        public Image Image
        {
            get { return image; }
            set
            {
                image = value;
                if (ImageChanged != null)
                    ImageChanged(this, new EventArgs());
            }
        }

        [DefaultValue(WrapMode.Tile)]
        public WrapMode ImageWrapMode
        {
            get { return wrap; }
            set
            {
                if (wrap != value)
                {
                    wrap = value;
                    if (ImageWrapModeChanged != null)
                        ImageWrapModeChanged(this, new EventArgs());
                }
            }
        }

        [DefaultValue(HatchStyle.Horizontal)]
        public HatchStyle Pattern
        {
            get { return pattern; }
            set
            {
                if (pattern != value)
                {
                    pattern = value;
                    if (PatternChanged != null)
                        PatternChanged(this, new EventArgs());
                }
            }
        }

        [DefaultValue(FillStyle.Solid)]
        public FillStyle Style
        {
            get { return style; }
            set
            {
                if (style != value)
                {
                    style = value;
                    if (StyleChanged != null)
                        StyleChanged(this, new EventArgs());
                }
            }
        }

        [DefaultValue(255)]
        public int Transparency
        {
            get { return transparency; }
            set
            {
                if (value < 0 || value > 255)
                    throw new ArgumentOutOfRangeException("value", value, "Transparency must be a value between 0 and 255");
                if (transparency != value)
                {
                    transparency = value;
                    if (TransparencyChanged != null)
                        TransparencyChanged(this, new EventArgs());
                }
            }
        }

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        public Brush GetBrush(RectangleF rect, GraphicsPath path)
        {
            Brush b = null;
            LinearGradientBrush lb;
            PathGradientBrush pgb;
            RectangleF bnds = path.GetBounds();
            Color c1 = Color.FromArgb(transparency, color1);
            Color c2 = Color.FromArgb(transparency, color2);
            Blend blend = new Blend();
            blend.Factors = new float[] { 0f, 0.5f, 1f };
            blend.Positions = new float[] { 0f, (center + 1f)/2, 1f };

            switch (style)
            {
                case FillStyle.None:
                    break;
                case FillStyle.Solid:
                default:
                    b = new SolidBrush(c1);
                    break;
                case FillStyle.Image:
                    if (image != null)
                        b = new TextureBrush(image, wrap);//, bnds);
                    break;
                case FillStyle.Pattern:
                    b = new HatchBrush(pattern, c1, c2);
                    break;
                case FillStyle.LinearGradient:
                    lb = new LinearGradientBrush(bnds, c1, c2, angle, true);
                    lb.GammaCorrection = true;
                    lb.Blend = blend;
                    b = lb;
                    break;
                case FillStyle.ABALinearGradient:
                    lb = new LinearGradientBrush(bnds, c1, c2, angle, true);
                    lb.GammaCorrection = true;
                    blend.Factors = new float[] { 0f, 1f, 0f };
                    blend.Positions = new float[] { 0f, (center + 1f)/2, 1f };
                    //blend.Factors = new float[] { 0f, 0f, 1f, 0f, 0f };
                    //blend.Positions = new float[] { 0f, 0.5f-((center+1f)/4f), 0.5f, 0.5f+((center+1f)/4f), 1f };
                    lb.Blend = blend;
                    b = lb;
                    break;
                case FillStyle.RadialGradient:
                    GraphicsPath radialPath = new GraphicsPath();
                    radialPath.AddEllipse(-1,-1,2,2);
                    pgb = new PathGradientBrush(radialPath);
                    float rad = (float)Math.Sqrt(Math.Pow(bnds.Width/2, 2) + Math.Pow(bnds.Height/2, 2));
                    pgb.ScaleTransform(rad, rad, MatrixOrder.Append);
                    pgb.TranslateTransform(bnds.Width/2f, bnds.Height/2f, MatrixOrder.Append);
                    goto PathGradientCommon;
                case FillStyle.RectangularGradient:
                    GraphicsPath rectPath = new GraphicsPath();
                    rectPath.AddRectangle(bnds);
                    pgb = new PathGradientBrush(rectPath);
                    goto PathGradientCommon;
                case FillStyle.PathGradient:
                    pgb = new PathGradientBrush(path);
                    PathGradientCommon:
                    pgb.CenterColor = c2;
                    pgb.SurroundColors = new Color[] { c1 };
                    pgb.Blend = blend;
                    b = pgb;
                    break;
            }

            /*if (style != ShapeGradientStyle.None && rect.Width > 0 && rect.Height > 0)
            {
                int iMode = (int)style;
                LinearGradientBrush lb;
                PathGradientBrush pgb = new PathGradientBrush(path);
                RectangleF bnds = path.GetBounds();

                switch (style)
                {
                    case ShapeGradientStyle.VerticalLeft:
                    case ShapeGradientStyle.VerticalRight:
                    case ShapeGradientStyle.HorizontalUp:
                    case ShapeGradientStyle.HorizontalDown:
                    case ShapeGradientStyle.DiagonalForwardBottom:
                    case ShapeGradientStyle.DiagonalForwardTop:
                    case ShapeGradientStyle.DiagonalBackwardBottom:
                    case ShapeGradientStyle.DiagonalBackwardTop:
                        lb = new LinearGradientBrush(PaintRect, (0 == iMode % 2) ? color1 : color2, (0 == iMode % 2) ? color2 : color1, (LinearGradientMode)((iMode-1)/4));
                        lb.GammaCorrection = true;
                        b = lb;
                        break;
                    case ShapeGradientStyle.VerticalIn:
                    case ShapeGradientStyle.VerticalOut:
                    case ShapeGradientStyle.HorizontalIn:
                    case ShapeGradientStyle.HorizontalOut:
                        Rectangle halfrect = rect;
                        if (iMode <= 4)
                            halfrect.Width /= 2;
                        else
                            halfrect.Height /= 2;
                        lb = new LinearGradientBrush(halfrect, (1 == iMode % 2) ? color1 : color2, (1 == iMode % 2) ? color2 : color1, (LinearGradientMode)((iMode-1)/4));
                        lb.GammaCorrection = true;
                        lb.WrapMode = WrapMode.TileFlipX;
                        b = lb;
                        break;
                    case ShapeGradientStyle.FromTopLeftCorner:
                        pgb.CenterPoint = bnds.Location;
                        goto corner;
                    case ShapeGradientStyle.FromTopRightCorner:
                        pgb.CenterPoint = new PointF(bnds.Right, bnds.Top);
                        goto corner;
                    case ShapeGradientStyle.FromBottomLeftCorner:
                        pgb.CenterPoint = new PointF(bnds.Left, bnds.Bottom);
                        goto corner;
                    case ShapeGradientStyle.FromBottomRightCorner:
                        pgb.CenterPoint = new PointF(bnds.Right, bnds.Bottom);
                        corner:
                            pgb.CenterColor = color1;
                        pgb.SurroundColors = new Color[] { color2 };
                        b = pgb;
                        break;
                    case ShapeGradientStyle.DiagonalForwardIn:
                    case ShapeGradientStyle.DiagonalForwardOut:
                        lb = new LinearGradientBrush(bnds.Location, new PointF((bnds.Right-bnds.Left)/2, (bnds.Bottom-bnds.Top)/2), (1 == iMode % 2) ? color1 : color2, (1 == iMode % 2) ? color2 : color1);
                        lb.GammaCorrection = true;
                        lb.WrapMode = WrapMode.TileFlipX;
                        b = lb;
                        break;
                    case ShapeGradientStyle.DiagonalBackwardIn:
                    case ShapeGradientStyle.DiagonalBackwardOut:
                        lb = new LinearGradientBrush(new PointF(bnds.Right, bnds.Top), new PointF((bnds.Right-bnds.Left)/2, (bnds.Bottom-bnds.Top)/2), (1 == iMode % 2) ? color1 : color2, (1 == iMode % 2) ? color2 : color1);
                        lb.GammaCorrection = true;
                        lb.WrapMode = WrapMode.TileFlipX;
                        b = lb;
                        break;
                    case ShapeGradientStyle.FromCenterIn:
                    case ShapeGradientStyle.FromCenterOut:
                    default:
                        pgb.CenterColor = (0 == iMode % 2) ? color1 : color2;
                        pgb.SurroundColors = new Color[] { (0 == iMode % 2) ? color2 : color1 };
                        b = pgb;
                        break;
                }
            }
            else*/

            return b;
        }

        /*private ImageLayoutMode imageLayout;
        public event EventHandler ImageLayoutChanged;
        public ImageLayoutMode ImageLayout
        {
            get { return imageLayout; }
            set
            {
                if (imageLayout != value)
                {
                    imageLayout = value;
                    if (ImageLayoutChanged != null)
                        ImageLayoutChanged(this, new EventArgs());
                }
            }
        }*/
    }
}